import json
import tornado.web
import tornado.websocket

# 自建
import entity
import globalData
import utils


# 编辑websocket类
class GameClientHandler(tornado.websocket.WebSocketHandler):

    # 处理新的 WebSocket 连接
    def open(self):
        client_id = self.request.query_arguments['id'][0].decode()
        chess_id = self.request.query_arguments['chess_id'][0].decode()
        self.id = client_id
        globalData.clients[self.id] = self
        print("已成功连接id:", self.id)
        # 发送id到客户端存储
        # self.on_message(entity.MessageResponse('id', self.id, None).parseJsonStr())
        if chess_id == "":
            chess_id = None
        self.chess_id = chess_id

        # 接收消息并进行处理

    def on_message(self, message):
        self.write_message(f"{message}")

    # 处理 WebSocket 关闭连接
    def on_close(self):
        print("WebSocket closed id:", self.id)
        globalData.clients.pop(self.id)

        # 检查棋局中是否2个用户均掉线，如果掉线，删除棋局
        if self.chess_id is None or self.chess_id == "":
            return

        chess = globalData.chesses[self.chess_id]
        other_p = ""
        print("这里",chess.p1.id)
        print("这里", chess.p2.id)

        if chess.p1.id == self.id:
            other_p = chess.p2.id
        else:
            other_p = chess.p1.id

        # 两个都掉线了
        if globalData.clients.get(other_p) is None:
            # print("销毁棋局")
            globalData.chesses.pop(self.chess_id)

    # 加入棋局
    def add_chess(self, chess_id):
        self.chess_id = chess_id

    # 设置允许的跨域来源
    def check_origin(self, origin):
        return True


'''
PvpHandler类

get方法参数：
    无
    
post方法参数：
    p_id:玩家id（必填）
    create:创建棋局标识符（创建棋局必填）
    size:棋局大小（创建棋局必填）
    chess_id:棋局id（加入棋局必填）
    
    注意：create，chess_id单独存在，不能同时存在
'''


class PvpHandler(tornado.web.RequestHandler):
    def set_default_headers(self):
        self.set_header("Access-Control-Allow-Origin", "*")  # 允许的源，替换为你的前端地址
        self.set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")  # 允许的请求方法
        self.set_header("Access-Control-Allow-Headers", "Content-Type")  # 允许的请求头

    # get方法用于获取pvp棋局列表
    async def get(self):
        # 接收参数
        # print(self.request.arguments)
        self.write(utils.parseChessesToJsonStr())
        pass

    # post方法用于建立pvp棋局
    async def post(self):
        params = self.request.query_arguments
        print(params)
        p_id = params['p_id'][0].decode()
        if params.get("create") is not None:
            # 先查询该用户（玩家是否已经加入棋局）
            player = globalData.clients[p_id]
            if globalData.chesses.get(player.chess_id) is not None:
                self.write(json.dumps({'msg': '该用户已加入棋局，请重新加入', 'error': 'true'}))
                return
            # 创建棋局
            size = int(params['size'][0].decode())

            chess_game = entity.ChessGame(size)
            chess_game.addPlayer(p_id)
            globalData.chesses[chess_game.id] = chess_game
            globalData.clients[p_id].add_chess(chess_game.id)
            # 发送广播到所有人中，用于刷新pvp棋局列表
            msg = entity.MessageResponse('updatePvpList', p_id, utils.parseChessesToJsonStr()).parseJsonStr()
            for _, v in globalData.clients.items():
                v.on_message(msg)
            # 返回棋盘信息，并返回创建成功
            self.write(json.dumps({'msg': '创建成功，正在等待玩家2加入', 'chess_id': chess_game.id, 'error': 'false'}))
            return

        if params.get('chess_id') is None:
            self.write(json.dumps({'msg': '参数不足', 'error': 'true'}))
            return
        chess_id = params['chess_id'][0].decode()
        if globalData.chesses.get(chess_id) is None:
            self.write(json.dumps({'msg': '没有该棋局', 'error': 'true'}))
            return

        # 去重
        player = globalData.clients[p_id]
        if player.chess_id is not None:
            self.write(json.dumps({'msg': '该用户已加入棋局，请退出后在重新加入', 'error': 'true'}))
            return
        chess_game = globalData.chesses[chess_id]
        # 给棋局加入p2
        chess_game.addPlayer(p_id)
        # 给p2加入棋局
        globalData.clients[p_id].add_chess(chess_game.id)
        p1_id = chess_game.p1.id
        p2_id = chess_game.p2.id
        # 设置p2玩家已经下过棋，让p1玩家先下棋
        chess_game.setCurrPlayer(p2_id)

        p1_ws = globalData.clients[p1_id]
        p2_ws = globalData.clients[p2_id]

        # 发送确认开局信息
        msg1 = entity.MessageResponse('playgame', p2_id, chess_game.getBoard()).parseJsonStr()
        msg2 = entity.MessageResponse('playgame', p1_id, chess_game.getBoard()).parseJsonStr()
        p1_ws.on_message(msg1)
        p2_ws.on_message(msg2)

        self.write(json.dumps({'msg': '棋局建立成功，玩家1——id：' + p1_id + '，玩家2——id：' + p2_id, 'error': 'false'}))
        return


'''
BoardAdapter类


post方法参数
    chess_id:当前棋局id
    col:当前棋子的纵向坐标
    row:当前棋子的横向战坐标
    send_p_id:发送消息的玩家id

'''


class BoardAdapterHandler(tornado.web.RequestHandler):
    def set_default_headers(self):
        self.set_header("Access-Control-Allow-Origin", "*")  # 允许的源，替换为你的前端地址
        self.set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")  # 允许的请求方法
        self.set_header("Access-Control-Allow-Headers", "Content-Type")  # 允许的请求头

    def get(self):
        self.write("get方法")

    def post(self):
        params = self.request.query_arguments
        if params.get('chess_id') is None or params.get('col') is None or params.get('row') is None \
                or params.get('send_p_id') is None:
            self.write({'msg': '参数不足', 'error': 'true'})
            return
        chess_id = params.get('chess_id')[0].decode()
        col = int(params.get('col')[0].decode())
        row = int(params.get('row')[0].decode())
        send_p_id = params.get('send_p_id')[0].decode()
        print(chess_id, col, row, send_p_id)
        # 寻找棋局
        if globalData.chesses.get(chess_id) is None:
            self.write(json.dumps({"msg": '发送失败，棋局被销毁了', 'error': 'true'}))
            return
        chess = globalData.chesses.get(chess_id)
        # 如果当前下棋的人与上一个人相同时，下棋失败
        if chess.last_p_id == send_p_id:
            self.write(json.dumps({"msg": '下棋失败，未到你下棋回合', 'error': 'true'}))
            return

        p1 =  chess.p1.id
        p2 =  chess.p2.id
        player = None
        if send_p_id ==p1:
            player =chess.p1
        else:
            player = chess.p2
        if player.play(chess.board, row, col):
            # 将信息保存到history列表中
            chess.history.append([row, col])

            msg = entity.MessageResponse('setChessPos'
                                         , send_p_id
                                         , json.dumps({'board': chess.getBoard()
                                                          , 'set_color': player.color
                                                          , 'pos': '(' + str(row) + ',' + str(col) + ')'})) \
                .parseJsonStr()
            globalData.clients[p1].on_message(msg)
            globalData.clients[p2].on_message(msg)
            # 检查棋局是否有胜负
            if chess.board.check_win(row, col, player.color):
                mm = json.dumps({"msg": '游戏结束', 'win_id': player.id, 'win_color': player.color, 'error': 'false'})
                msg2 = entity.MessageResponse('gameEnd', send_p_id, mm).parseJsonStr()
                globalData.clients[p1].on_message(msg2)
                globalData.clients[p2].on_message(msg2)
                # 删除该对局信息
                globalData.chesses.pop(chess.id)
                return
            else:
                # 设置新下棋人
                chess.setCurrPlayer(send_p_id)
            self.write(json.dumps({"msg": '下棋成功', 'error': 'false'}))
        else:
            self.write(json.dumps({"msg": '下棋失败，你不想下不要下，别乱搞', 'error': 'true'}))


'''
ExitChessHandler类

作用：退出该玩家所在棋局，若该棋局只有一名玩家，销毁棋局

post方法参数
    send_p_id:发送消息的玩家id
'''


class ExitChessHandler(tornado.web.RequestHandler):
    # 解决跨域
    def set_default_headers(self):
        self.set_header("Access-Control-Allow-Origin", "*")  # 允许的源，替换为你的前端地址
        self.set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")  # 允许的请求方法
        self.set_header("Access-Control-Allow-Headers", "Content-Type")  # 允许的请求头

    def get(self):
        pass

    def post(self):
        params = self.request.query_arguments
        send_p_id = params['send_p_id'][0].decode()
        if globalData.clients.get(send_p_id) is None:
            self.write(json.dumps({'msg': '请刷新页面重新连接服务器', 'error': 'true'}))
            return
        send_p = globalData.clients[send_p_id]
        # 查询棋局
        if globalData.chesses.get(send_p.chess_id) is None:
            self.write(json.dumps({'msg': '该棋局不存在', 'error': 'true'}))
            return

        chess = globalData.chesses[send_p.chess_id]
        p1 = chess.p1.id
        p2=''
        if chess.p2 is not None:
            p2 = chess.p2.id
        if p2 == '':
            globalData.chesses.pop(send_p.chess_id)
            send_p.chess_id = None
            # 发送广播到所有人中，用于刷新pvp棋局列表
            msg = entity.MessageResponse('updatePvpList', send_p_id, utils.parseChessesToJsonStr()).parseJsonStr()
            for _, v in globalData.clients.items():
                v.on_message(msg)
            self.write(json.dumps({'msg': '退出棋局成功', 'error': 'false'}))
            return

        # 重置棋盘
        chess.board = entity.Board(chess.size)
        player_other = None
        if p1 == send_p_id:
            send_p.chess_id = None
            chess.p1 = None
            player_other = globalData.clients[p2]
        else:
            send_p.chess_id = None
            chess.p2 = None
            player_other = globalData.clients[p1]

        # 发送信息重新等待玩家
        msg = entity.MessageResponse('waitPlayer', send_p_id, json.dumps({"chess_id": chess.id})).parseJsonStr()
        player_other.on_message(msg)
        self.write(json.dumps({'msg': '退出棋局成功', 'error': 'false'}))


'''
BackChessHandler类

作用：悔棋

post方法参数
    
'''

class BackChessHandler(tornado.web.RequestHandler):
    # 解决跨域
    def set_default_headers(self):
        self.set_header("Access-Control-Allow-Origin", "*")  # 允许的源，替换为你的前端地址
        self.set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")  # 允许的请求方法
        self.set_header("Access-Control-Allow-Headers", "Content-Type")  # 允许的请求头

    def get(self):
        pass

    def post(self):
        # chess_id p_id
        params = self.request.query_arguments
        chess_id = params['chess_id'][0].decode()
        p_id = params['p_id'][0].decode()
        other_id = params['other_id'][0].decode()

        chess = globalData.chesses.get(chess_id)
        if chess is None:
            self.write(json.dumps({'msg': '无该棋局', 'error': 'true'}))
            return

        last_p_id = chess.last_p_id
        if len(chess.history) == 0:
            self.write(json.dumps({'msg': '刚开局，不需要悔棋', 'error': 'true'}))
            return

        if last_p_id != p_id:
            self.write(json.dumps({'msg': '对方已经下棋，您不能悔棋了', 'error': 'true'}))
            return

        t = chess.history.pop()

        chess.board.back(t[0],t[1])
        chess.last_p_id = other_id
        color = ''
        if chess.p1.id == p_id:
            color = chess.p1.color
        else:
            color = chess.p2.color

        self.write(json.dumps({'msg': '悔棋成功', 'error': 'false'}))
        mm = json.dumps({"msg": '悔棋成功','chess_board':chess.getBoard(),'back_pos':'('+str(t[0])+','+str(t[1])+')','back_color':color, 'error': 'false'})
        msg2 = entity.MessageResponse('backChess', p_id, mm).parseJsonStr()
        globalData.clients[p_id].on_message(msg2)
        globalData.clients[other_id].on_message(msg2)
        return

